package de.stefanocke.roo.wicket.base

import java.util.List
import org.springframework.roo.model.JavaType
import static extension java.util.Collections.*
import static extension de.stefanocke.roo.wicket.base.ComponentFilter.*
import static extension de.stefanocke.roo.wicket.base.MetadataFilter.*
import de.stefanocke.roo.wicket.model.BeanPropertyMetadata


class ComponentFilter {
	
	def static <C extends ComponentMetadata> filter(String requestingMid, BeanPropertyMetadata propertyMetadata){		
		<C>filter(requestingMid, propertyMetadata.effectiveAnnotations.map[annotationType])
	}
	
	//closure that filters a list of objects having ComponentFilterAttributes and leaves only the ones that
	//have no more requiredAnnotations than the given ones and, amongst them, 
	//have the highest number of required annotations (that is "the most specific ones")
	def static <C extends ComponentFilterAttributes> filter(List<JavaType> annotations){		
		[Iterable<C> iterable | iterable
				.filterByRequiredAnnotations(annotations)
				.filterByMaxAnnotations
		]
	}
	
	//closure that filters a list of component metadata and leaves only the ones that
	//have no more requiredAnnotations than the given ones and,
	//amongst them, only the ones are that are closest to the given metadata 
	//(considering package distance of the governor) and,
	// amongst them, have the highest number of required annotations (that is "the most specific ones")
	//
	//TODO: This might be quite confusing. Perhaps it's better not to filter for the nearest.
	//Instead it might be better to look for the module. For example, an admin portal might need other 
	//components than a user portal. The portals are put into 2 seperate modules and component search ist restricted
	//to the respective module.
	
	def static <C extends ComponentMetadata> filter(String requestingMid, List<JavaType> annotations){
		
		[Iterable<C> iterable | iterable
				.filterByRequiredAnnotations(annotations)
				.filterClosest(requestingMid)
				.filterByMaxAnnotations
		]
	}
	
	def static <C extends ComponentFilterAttributes> 
	filterByRequiredAnnotations(Iterable<C> iterable, List<JavaType> annotations){
		iterable.filter[annotations.containsAll(it.requiredAnnotations)]
	}
	
	def static <C extends ComponentFilterAttributes> filterByMaxAnnotations(Iterable<C> iterable){
		if(iterable.empty) iterable else {
			val max = iterable.map[requiredAnnotations.size].toSet.max;
			iterable.filter[requiredAnnotations.size==max]
		}
	}
}